import util from '@ohos.util';
import { JSON } from '@kit.ArkTS';
import JsLogger from './JsLogger';
import JsDataStore from './JsDataStore';
import pasteboard from '@ohos.pasteboard';
import { BusinessError } from '@ohos.base';
import abilityAccessCtrl, { PermissionRequestResult } from '@ohos.abilityAccessCtrl';

export class JsPasteBoard {
  private encoder: util.TextEncoder = util.TextEncoder.create('utf-8');
  private decoder: util.TextDecoder = util.TextDecoder.create('utf-8');
  private strType: Array<string> =
    [pasteboard.MIMETYPE_TEXT_HTML, pasteboard.MIMETYPE_TEXT_PLAIN, pasteboard.MIMETYPE_TEXT_URI];

  constructor() {
    let systemPasteboard = pasteboard.getSystemPasteboard();
    systemPasteboard.on('update', () => {
      JsDataStore.getQtNativeModule("QPA").pasteChanged();
    });
  }

  private systemPasteData(): pasteboard.PasteData {
    let systemPasteboard = pasteboard.getSystemPasteboard();
    return systemPasteboard.getDataSync();
  }

  private async requestPermissionsFromUser(): Promise<void> {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    await atManager.requestPermissionsFromUser(JsDataStore.getValidContext(), ['ohos.permission.READ_PASTEBOARD'])
      .then((data: PermissionRequestResult) => {
        console.info('data:' + JSON.stringify(data));
        console.info('data permissions:' + data.permissions);
        console.info('data authResults:' + data.authResults);
      }).catch((err: BusinessError) => {
        console.error('data:' + JSON.stringify(err));
      });
  }

  hasType(type: string): boolean {
    let result: boolean = false;
    let systemPasteboard = pasteboard.getSystemPasteboard();
    try {
      result = systemPasteboard.hasDataType(type);
    } catch (err) {
      JsLogger.error(`Failed to check the DataType. Case:` + err.message);
    }
    return result;
  }

  mimeTypes(): Array<string> {
    let sysPasteData = this.systemPasteData();
    return sysPasteData.getMimeTypes();
  }

  async data(mimeType: string): Promise<ArrayBuffer> {
    let sysPasteData = this.systemPasteData();
    try {
      await this.requestPermissionsFromUser();
    } catch (e) {
      JsLogger.error(`requestPermissionsFromUser failed, Case:${e.message}`);
    }
    sysPasteData.pasteStart();
    if (!sysPasteData.hasType(mimeType)) {
      return new ArrayBuffer(0);
    }

    let data: ArrayBuffer = new ArrayBuffer(0);
    for (let i = 0; i < sysPasteData.getRecordCount(); ++i) {
      let record: pasteboard.PasteDataRecord = sysPasteData.getRecord(i);
      if (record.mimeType !== mimeType) {
        continue;
      }
      try {
        /* NOTE 对接口定义的textHtm,textPlain不能直接读Record中的data */
        if (mimeType === pasteboard.MIMETYPE_TEXT_HTML) {
          let result: Uint8Array = this.encoder.encodeInto(record.htmlText);
          data = result.buffer.slice(0);
        } else if (mimeType === pasteboard.MIMETYPE_TEXT_PLAIN) {
          let result: Uint8Array = this.encoder.encodeInto(record.plainText);
          data = result.buffer.slice(0);
        } else if (mimeType === pasteboard.MIMETYPE_TEXT_URI) {
          let result: Uint8Array = this.encoder.encodeInto(record.uri);
          data = result.buffer.slice(0);
        } else {
          data = record.data[mimeType].slice(0);
        }
      } catch (err) {
        JsLogger.error(`get data failed mimeType:${mimeType} message:${err.message}`);
      }
    }
    sysPasteData.pasteComplete();
    return data;
  }

  async setData(mimeType: string, data: ArrayBuffer) {
    try {
      await this.requestPermissionsFromUser();
    } catch (e) {
      JsLogger.error(`requestPermissionsFromUser failed, Case:${e.message}`);
    }
    try {
      let sysPasteData = this.systemPasteData();
      if (sysPasteData.hasType(mimeType)) {
        for (let i = 0; i < sysPasteData.getRecordCount(); ++i) {
          let record: pasteboard.PasteDataRecord = sysPasteData.getRecord(i);
          if (record.mimeType !== mimeType) {
            continue;
          }
          if (mimeType === pasteboard.MIMETYPE_TEXT_HTML) {
            record.htmlText = this.decoder.decodeToString(new Uint8Array(data));
          } else if (mimeType === pasteboard.MIMETYPE_TEXT_PLAIN) {
            record.plainText = this.decoder.decodeToString(new Uint8Array(data));
          } else if (mimeType === pasteboard.MIMETYPE_TEXT_URI) {
            record.uri = this.decoder.decodeToString(new Uint8Array(data));
          } else {
            record.data[mimeType] = data;
          }
          sysPasteData.replaceRecord(i, record);
        }
      } else {
        if (this.strType.includes(mimeType)) {
          /* NOTE 接口限制了html,uri plainText 的数据必须为string */
          let str: string = this.decoder.decodeToString(new Uint8Array(data));
          sysPasteData.addRecord(mimeType, str);
        } else {
          sysPasteData.addRecord(mimeType, data);
        }
      }
      this.setPasteData(sysPasteData);
    } catch (err) {
      JsLogger.error(`set ${mimeType} pastebord data failed:${err.message} data length:${data.byteLength}`);
    }
  }

  setPasteData(data: pasteboard.PasteData) {
    let systemPasteboard = pasteboard.getSystemPasteboard();
    try {
      systemPasteboard.setDataSync(data);
    } catch (err) {
      JsLogger.error(`Failed to set PasteData. Cause:` + err.message);
    }
  }

  clearData() {
    let systemPasteboard = pasteboard.getSystemPasteboard();
    systemPasteboard.clearDataSync();
    return true;
  }
}
